{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Working with Internal Representations"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "from pymbolic import parse\n",
    "\n",
    "x = parse(\"x\")\n",
    "h = parse(\"h\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Visualizing an Expression Tree"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "u = (x+4)**3\n",
    "\n",
    "h = parse(\"h\")\n",
    "\n",
    "expr = u + 2*u*h + 4*u*h**2\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "# Load an IPython extension for graph drawing\n",
    "%load_ext gvmagic"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "from pymbolic.mapper.graphviz import GraphvizMapper\n",
    "\n",
    "gvm = GraphvizMapper()\n",
    "gvm(expr)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "image/svg+xml": [
       "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n",
       "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n",
       " \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n",
       "<!-- Generated by graphviz version 2.38.0 (20140413.2041)\n",
       " -->\n",
       "<!-- Title: expression Pages: 1 -->\n",
       "<svg width=\"374pt\" height=\"332pt\"\n",
       " viewBox=\"0.00 0.00 374.00 332.00\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n",
       "<g id=\"graph0\" class=\"graph\" transform=\"scale(1 1) rotate(0) translate(4 328)\">\n",
       "<title>expression</title>\n",
       "<polygon fill=\"white\" stroke=\"none\" points=\"-4,4 -4,-328 370,-328 370,4 -4,4\"/>\n",
       "<!-- id139763482266984 -->\n",
       "<g id=\"node1\" class=\"node\"><title>id139763482266984</title>\n",
       "<ellipse fill=\"none\" stroke=\"black\" cx=\"177\" cy=\"-306\" rx=\"18\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"177\" y=\"-302.3\" font-family=\"Times,serif\" font-size=\"14.00\">+</text>\n",
       "</g>\n",
       "<!-- id139763482267040 -->\n",
       "<g id=\"node2\" class=\"node\"><title>id139763482267040</title>\n",
       "<ellipse fill=\"none\" stroke=\"black\" cx=\"177\" cy=\"-162\" rx=\"33.2948\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"177\" y=\"-158.3\" font-family=\"Times,serif\" font-size=\"14.00\">Power</text>\n",
       "</g>\n",
       "<!-- id139763482266984&#45;&gt;id139763482267040 -->\n",
       "<g id=\"edge1\" class=\"edge\"><title>id139763482266984&#45;&gt;id139763482267040</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M177,-287.871C177,-263.67 177,-219.211 177,-190.393\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"180.5,-190.189 177,-180.189 173.5,-190.189 180.5,-190.189\"/>\n",
       "</g>\n",
       "<!-- id139763482267096 -->\n",
       "<g id=\"node7\" class=\"node\"><title>id139763482267096</title>\n",
       "<ellipse fill=\"none\" stroke=\"black\" cx=\"115\" cy=\"-234\" rx=\"18\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"115\" y=\"-230.3\" font-family=\"Times,serif\" font-size=\"14.00\">*</text>\n",
       "</g>\n",
       "<!-- id139763482266984&#45;&gt;id139763482267096 -->\n",
       "<g id=\"edge6\" class=\"edge\"><title>id139763482266984&#45;&gt;id139763482267096</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M165.338,-291.834C156.332,-281.665 143.7,-267.403 133.343,-255.71\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"135.86,-253.273 126.609,-248.107 130.62,-257.914 135.86,-253.273\"/>\n",
       "</g>\n",
       "<!-- id139763482267264 -->\n",
       "<g id=\"node10\" class=\"node\"><title>id139763482267264</title>\n",
       "<ellipse fill=\"none\" stroke=\"black\" cx=\"242\" cy=\"-234\" rx=\"18\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"242\" y=\"-230.3\" font-family=\"Times,serif\" font-size=\"14.00\">*</text>\n",
       "</g>\n",
       "<!-- id139763482266984&#45;&gt;id139763482267264 -->\n",
       "<g id=\"edge10\" class=\"edge\"><title>id139763482266984&#45;&gt;id139763482267264</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M188.922,-292.161C198.543,-281.8 212.25,-267.038 223.325,-255.111\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"225.914,-257.467 230.154,-247.758 220.784,-252.704 225.914,-257.467\"/>\n",
       "</g>\n",
       "<!-- id139763482266928 -->\n",
       "<g id=\"node3\" class=\"node\"><title>id139763482266928</title>\n",
       "<ellipse fill=\"none\" stroke=\"black\" cx=\"117\" cy=\"-90\" rx=\"18\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"117\" y=\"-86.3\" font-family=\"Times,serif\" font-size=\"14.00\">+</text>\n",
       "</g>\n",
       "<!-- id139763482267040&#45;&gt;id139763482266928 -->\n",
       "<g id=\"edge2\" class=\"edge\"><title>id139763482267040&#45;&gt;id139763482266928</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M163.684,-145.465C155.21,-135.579 144.133,-122.655 134.895,-111.878\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"137.429,-109.456 128.264,-104.141 132.114,-114.011 137.429,-109.456\"/>\n",
       "</g>\n",
       "<!-- uid2 -->\n",
       "<g id=\"node6\" class=\"node\"><title>uid2</title>\n",
       "<ellipse fill=\"none\" stroke=\"black\" cx=\"180\" cy=\"-90\" rx=\"27\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"180\" y=\"-86.3\" font-family=\"Times,serif\" font-size=\"14.00\">3</text>\n",
       "</g>\n",
       "<!-- id139763482267040&#45;&gt;uid2 -->\n",
       "<g id=\"edge5\" class=\"edge\"><title>id139763482267040&#45;&gt;uid2</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M177.742,-143.697C178.072,-135.983 178.469,-126.712 178.838,-118.112\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"182.335,-118.245 179.267,-108.104 175.342,-117.945 182.335,-118.245\"/>\n",
       "</g>\n",
       "<!-- uid0 -->\n",
       "<g id=\"node4\" class=\"node\"><title>uid0</title>\n",
       "<polygon fill=\"none\" stroke=\"black\" points=\"108,-36 54,-36 54,-0 108,-0 108,-36\"/>\n",
       "<text text-anchor=\"middle\" x=\"81\" y=\"-14.3\" font-family=\"Times,serif\" font-size=\"14.00\">x</text>\n",
       "</g>\n",
       "<!-- id139763482266928&#45;&gt;uid0 -->\n",
       "<g id=\"edge3\" class=\"edge\"><title>id139763482266928&#45;&gt;uid0</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M109.01,-73.4647C104.785,-65.2479 99.4796,-54.9325 94.6261,-45.4952\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"97.6659,-43.753 89.9799,-36.4609 91.4409,-46.9545 97.6659,-43.753\"/>\n",
       "</g>\n",
       "<!-- uid1 -->\n",
       "<g id=\"node5\" class=\"node\"><title>uid1</title>\n",
       "<ellipse fill=\"none\" stroke=\"black\" cx=\"153\" cy=\"-18\" rx=\"27\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"153\" y=\"-14.3\" font-family=\"Times,serif\" font-size=\"14.00\">4</text>\n",
       "</g>\n",
       "<!-- id139763482266928&#45;&gt;uid1 -->\n",
       "<g id=\"edge4\" class=\"edge\"><title>id139763482266928&#45;&gt;uid1</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M124.99,-73.4647C129.385,-64.9181 134.948,-54.1011 139.956,-44.3633\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"143.07,-45.9608 144.531,-35.4672 136.845,-42.7593 143.07,-45.9608\"/>\n",
       "</g>\n",
       "<!-- id139763482267096&#45;&gt;id139763482267040 -->\n",
       "<g id=\"edge8\" class=\"edge\"><title>id139763482267096&#45;&gt;id139763482267040</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M126.662,-219.834C135.017,-210.4 146.492,-197.444 156.377,-186.284\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"159.215,-188.358 163.226,-178.552 153.975,-183.717 159.215,-188.358\"/>\n",
       "</g>\n",
       "<!-- uid3 -->\n",
       "<g id=\"node8\" class=\"node\"><title>uid3</title>\n",
       "<ellipse fill=\"none\" stroke=\"black\" cx=\"99\" cy=\"-162\" rx=\"27\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"99\" y=\"-158.3\" font-family=\"Times,serif\" font-size=\"14.00\">2</text>\n",
       "</g>\n",
       "<!-- id139763482267096&#45;&gt;uid3 -->\n",
       "<g id=\"edge7\" class=\"edge\"><title>id139763482267096&#45;&gt;uid3</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M111.127,-216.055C109.345,-208.261 107.188,-198.822 105.189,-190.079\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"108.589,-189.244 102.949,-180.275 101.765,-190.804 108.589,-189.244\"/>\n",
       "</g>\n",
       "<!-- uid4 -->\n",
       "<g id=\"node9\" class=\"node\"><title>uid4</title>\n",
       "<polygon fill=\"none\" stroke=\"black\" points=\"54,-180 0,-180 0,-144 54,-144 54,-180\"/>\n",
       "<text text-anchor=\"middle\" x=\"27\" y=\"-158.3\" font-family=\"Times,serif\" font-size=\"14.00\">h</text>\n",
       "</g>\n",
       "<!-- id139763482267096&#45;&gt;uid4 -->\n",
       "<g id=\"edge9\" class=\"edge\"><title>id139763482267096&#45;&gt;uid4</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M101.25,-222.062C89.3403,-212.589 71.6996,-198.556 56.6011,-186.546\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"58.5321,-183.61 48.5272,-180.124 54.1744,-189.088 58.5321,-183.61\"/>\n",
       "</g>\n",
       "<!-- id139763482267264&#45;&gt;id139763482267040 -->\n",
       "<g id=\"edge12\" class=\"edge\"><title>id139763482267264&#45;&gt;id139763482267040</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M230.078,-220.161C221.204,-210.604 208.853,-197.303 198.298,-185.936\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"200.712,-183.392 191.342,-178.446 195.582,-188.155 200.712,-183.392\"/>\n",
       "</g>\n",
       "<!-- uid5 -->\n",
       "<g id=\"node11\" class=\"node\"><title>uid5</title>\n",
       "<ellipse fill=\"none\" stroke=\"black\" cx=\"339\" cy=\"-162\" rx=\"27\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"339\" y=\"-158.3\" font-family=\"Times,serif\" font-size=\"14.00\">4</text>\n",
       "</g>\n",
       "<!-- id139763482267264&#45;&gt;uid5 -->\n",
       "<g id=\"edge11\" class=\"edge\"><title>id139763482267264&#45;&gt;uid5</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M256.313,-222.671C271.167,-211.951 294.728,-194.949 312.906,-181.831\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"315.275,-184.438 321.336,-175.748 311.178,-178.761 315.275,-184.438\"/>\n",
       "</g>\n",
       "<!-- id139763482267208 -->\n",
       "<g id=\"node12\" class=\"node\"><title>id139763482267208</title>\n",
       "<ellipse fill=\"none\" stroke=\"black\" cx=\"261\" cy=\"-162\" rx=\"33.2948\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"261\" y=\"-158.3\" font-family=\"Times,serif\" font-size=\"14.00\">Power</text>\n",
       "</g>\n",
       "<!-- id139763482267264&#45;&gt;id139763482267208 -->\n",
       "<g id=\"edge13\" class=\"edge\"><title>id139763482267264&#45;&gt;id139763482267208</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M246.503,-216.411C248.671,-208.421 251.326,-198.642 253.768,-189.645\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"257.156,-190.524 256.398,-179.956 250.4,-188.69 257.156,-190.524\"/>\n",
       "</g>\n",
       "<!-- uid6 -->\n",
       "<g id=\"node13\" class=\"node\"><title>uid6</title>\n",
       "<polygon fill=\"none\" stroke=\"black\" points=\"285,-108 231,-108 231,-72 285,-72 285,-108\"/>\n",
       "<text text-anchor=\"middle\" x=\"258\" y=\"-86.3\" font-family=\"Times,serif\" font-size=\"14.00\">h</text>\n",
       "</g>\n",
       "<!-- id139763482267208&#45;&gt;uid6 -->\n",
       "<g id=\"edge14\" class=\"edge\"><title>id139763482267208&#45;&gt;uid6</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M260.258,-143.697C259.928,-135.983 259.531,-126.712 259.162,-118.112\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"262.658,-117.945 258.733,-108.104 255.665,-118.245 262.658,-117.945\"/>\n",
       "</g>\n",
       "<!-- uid7 -->\n",
       "<g id=\"node14\" class=\"node\"><title>uid7</title>\n",
       "<ellipse fill=\"none\" stroke=\"black\" cx=\"330\" cy=\"-90\" rx=\"27\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"330\" y=\"-86.3\" font-family=\"Times,serif\" font-size=\"14.00\">2</text>\n",
       "</g>\n",
       "<!-- id139763482267208&#45;&gt;uid7 -->\n",
       "<g id=\"edge15\" class=\"edge\"><title>id139763482267208&#45;&gt;uid7</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M275.972,-145.811C285.413,-136.234 297.762,-123.705 308.271,-113.044\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"311.003,-115.258 315.53,-105.68 306.017,-110.344 311.003,-115.258\"/>\n",
       "</g>\n",
       "</g>\n",
       "</svg>\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "#clear\n",
    "%dotstr gvm.get_dot_code()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Serialization"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The need may arise to store expressions on disk, likely as part of larger problem descriptions. One particular application of this might be caching. To do so, one can simply use Python's built-in 'pickle' mechanism:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'bytes'> 238\n",
      "True\n",
      "False\n"
     ]
    }
   ],
   "source": [
    "import pickle\n",
    "\n",
    "expr_data = pickle.dumps(expr)\n",
    "\n",
    "print(type(expr_data), len(expr_data))\n",
    "\n",
    "expr2 = pickle.loads(expr_data)\n",
    "\n",
    "print(expr2 == expr)\n",
    "print(expr2 is expr)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Caching"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Some operations on expression data (such as an entire compilation down to an OpenCL binary) may be somewhat expensive, which often makes caching a worthwhile investment. In principle, a Python dictionary is all that is needed, because the expression types that have been demonstrated are immutable and support hashing, and therefore work seamlessly with Python's set and dictionary types.\n",
    "\n",
    "In connection with caches, one important question that needs to be answered is cache lifetime. In the example below, this is answered by attaching the lifetime of the cash to the lifetime of a containing object:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "\n",
    "from pytools import memoize_method\n",
    "\n",
    "class ExpressionCompiler:\n",
    "    @memoize_method\n",
    "    def compile(self, expr):\n",
    "        print(\"compiling...\")\n",
    "        from time import sleep\n",
    "        sleep(1.5)\n",
    "\n",
    "        from pymbolic.mapper.c_code import CCodeMapper\n",
    "        ccm = CCodeMapper()\n",
    "        return ccm(expr)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "(`pytools` is a supporting package that `pymbolic` depends on.)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "compiling...\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'pow(x + 4, 3) + 4 * pow(x + 4, 3) * h * h + 2 * pow(x + 4, 3) * h'"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "ec = ExpressionCompiler()\n",
    "\n",
    "ec.compile(expr)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'pow(x + 4, 3) + 4 * pow(x + 4, 3) * h * h + 2 * pow(x + 4, 3) * h'"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "ec.compile(expr)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.5.0+"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
